#include "sys.h"
#include "log.h"
#include "timer.h"

static TIMER_LOCK_T Timer_lock;

void timer_show(struct Timer_head* head)
{
    struct timer_s* pdata;
    
    TIMER_LOCK(&Timer_lock);
    for (pdata = TAILQ_FIRST(head); pdata; pdata = TAILQ_NEXT(pdata, entry)) {
        log_debug("tmr :%p", pdata);
        log_tv("tmr expire:", &pdata->expire);
        log_tv("tmr tm:", &pdata->tm);
        log_debug("tmr cb:%p", pdata->cb);
    }
    TIMER_UNLOCK(&Timer_lock);
}

void timer_update(struct Timer_head* head)
{
    struct timer_s *pdata;
    struct timeval tm, now;

    gettimeofday(&now, NULL);
    for (pdata = TAILQ_FIRST(head); pdata; pdata = TAILQ_NEXT(pdata, entry)) {
        memcpy(&tm, &pdata->clock_tm, sizeof(tm));
        timersub(&pdata->clock_tm, &now, &pdata->tm);
    }
}
void timer_add(struct Timer_head* head, struct timer_s* new)
{
    struct timer_s* pdata;
    int flag = 0;

    assert(head != NULL);
    assert(new != NULL);

    TIMER_LOCK(&Timer_lock);
    if (TAILQ_EMPTY(head)) {
        new->tm.tv_sec = new->expire.tv_sec;
        new->tm.tv_usec = new->expire.tv_usec;
        TAILQ_INSERT_TAIL(head, new, entry);
        return;
    }

    for (pdata = TAILQ_FIRST(head); pdata; pdata = TAILQ_NEXT(pdata, entry)) {
        
        if (timercmp(&new->clock_tm, &pdata->clock_tm, <)) {
            TAILQ_INSERT_BEFORE(pdata, new, entry);
            flag = 1;
            break;
        }
    }
    if (!flag)
        TAILQ_INSERT_TAIL(head, new, entry);
    timer_update(head);
    TIMER_UNLOCK(&Timer_lock);
}
struct timer_s* timer_pop(struct Timer_head* head)
{
    TIMER_LOCK(&Timer_lock);
    struct timer_s* pdata = TAILQ_FIRST(head);
    if (pdata != NULL) {
        TAILQ_REMOVE(head, pdata, entry);
    }
    TIMER_UNLOCK(&Timer_lock);
    return pdata;
}
struct timer_s* timer_new(struct timeval* tm, tmr_cb cb)
{
    struct timer_s* tmr = malloc(sizeof(struct timer_s));
    if (!tmr) {
        log_syserr("calloc error.");
        return NULL;
    }
    bzero(tmr, sizeof(struct timer_s));
    gettimeofday(&tmr->clock_tm, NULL);
    tmr->expire.tv_sec = tm->tv_sec;
    tmr->expire.tv_usec = tm->tv_usec;
    timeradd(&tmr->expire, &tmr->clock_tm, &tmr->clock_tm);
    tmr->cb = cb;
    return tmr;
}
void timer_call(struct timer_s *tmr){
    if(tmr->cb){
        tmr->cb((void *)tmr);
    }
}
void timer_free(struct timer_s* tmr)
{
    free(tmr);
}
